package com.yonyou.pmclouds.procedure.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.util.CommonProgramConsts;
import com.yonyou.pmclouds.offline.aspect.Offline;
import com.yonyou.pmclouds.offline.entity.OffLineDataKeyConst;
import com.yonyou.pmclouds.offline.entity.OffLineInvocationContext;
import com.yonyou.pmclouds.offline.rmiitf.IOffLineDataQueryService;
import com.yonyou.pmclouds.procedure.entity.ProcedureRefVO;
import com.yonyou.pmclouds.procedure.entity.ProcedureVO;
import com.yonyou.pmclouds.procedure.entity.ProceprojectVO;
import com.yonyou.pmclouds.procedure.mapper.ProcedureMapper;
import com.yonyou.pmclouds.procedure.rmiitf.ProcedureQuery;
import com.yonyou.pmclouds.procedure.rmiitf.ProceprojectQryService;
import com.yonyou.pmclouds.project.rmiitf.ProjectSimpleQuery;
import com.yonyou.pmclouds.workquality.entity.WorkqualityVO;
import com.yonyou.pmclouds.workquality.service.rmiitf.WorkqualityQueryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

@Slf4j
@Service(interfaceClass = ProcedureQuery.class, version = ApplicationConsts.APPLICATION_VERSION)
@Offline(dataFrom = OffLineDataKeyConst.DATA_FROM_PROCEDURE)
public class ProcedureQueryImpl implements ProcedureQuery, IOffLineDataQueryService {
    @Autowired
    private ProcedureMapper mapper;
    @Autowired
    private ProjectSimpleQuery projectSimpleQuery;
    @Autowired
    private ProceprojectQryService proceprojectQryService;
    @Autowired
    private WorkqualityQueryService workqualityQueryService;

    @Override
    public ProcedureVO[] queryProcedureByTenant(String tenantid, byte enableStatus) throws BusinessException {
        try {
            return mapper.queryProceduresOfTenant(tenantid, enableStatus);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new BusinessException();
        }
    }

    @Override
    public ProcedureRefVO[] queryProcedureRefByTenant(String tenantid) throws BusinessException {
        try {
            return mapper.queryProceduresRefOfTenant(tenantid);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new BusinessException("获取工序失败" + ex.getMessage());
        }
    }

    @Override
    public ProcedureVO getById(String id) throws BusinessException {
        try {
            return mapper.getById(id);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new BusinessException();
        }
    }

    @Override
    public Map<String, ProcedureRefVO> queryRefs(String[] ids) throws BusinessException {
        if (ArrayUtils.isEmpty(ids)) {
            return new HashMap<>();
        }
        //强制截取长度，避免insql可能的问题
        if (ids.length > CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE) {
            ids = Arrays.copyOf(ids, CommonProgramConsts.DEFAULT_MAX_QUERY_SIZE);
        }
        // 这里不作权限控制
        ProcedureRefVO[] refs = null;
        try {
            refs = mapper.queryRefVOByIds(ids);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new BusinessException();
        }
        if (ArrayUtils.isEmpty(refs)) {
            return new HashMap<>();
        }
        Map<String, ProcedureRefVO> result = new HashMap<>(refs.length);
        for (ProcedureRefVO ref : refs) {
            result.put(ref.getPkProcedure(), ref);
        }
        return result;
    }

    @Override
    public ProcedureVO[] queryProcedureByRoots(String[] pkRoots) throws BusinessException {
        try {
            return mapper.queryProcedureByRoots(pkRoots);
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
            throw new BusinessException();
        }
    }

    @Override
    public Map<String, String> queryNameByIds(String[] ids) throws BusinessException {
        if (ArrayUtils.isEmpty(ids)) {
            return new HashMap<>();
        }
        ProcedureVO[] procedureVOS = mapper.queryNameByIds(ids);
        if (ArrayUtils.isEmpty(procedureVOS)) {
            return new HashMap<>();
        }
        Map<String, String> results = new HashMap<>(procedureVOS.length);
        for (ProcedureVO vo : procedureVOS
                ) {
            results.put(vo.getPkProcedure(), vo.getSname());
        }
        return results;
    }

    @Override
    public ProcedureRefVO[] queryRefByProject(String pkPro, String tenantId) throws BusinessException {

        if (StringUtils.isEmpty(pkPro))
            return new ProcedureRefVO[0];
        ProceprojectVO[] proceprojectVOS = proceprojectQryService.selectProceprojectByProjectId(pkPro);
        if (ArrayUtils.isEmpty(proceprojectVOS)) {
            return this.queryProcedureRefByTenant(tenantId);
        } else {
            java.lang.String[] ids = new String[proceprojectVOS.length];
            for (int i = 0; i < proceprojectVOS.length; i++) {
                ids[i] = proceprojectVOS[i].getPkProcedure();
            }
            ProcedureVO[] procedureVOS = mapper.queryProcedureByRoots(ids);

            return setProcedureInfo(procedureVOS);
        }
    }

    private ProcedureRefVO[] setProcedureInfo(ProcedureVO[] procedureVOS) {
        ProcedureRefVO[] procedureRefVOS = new ProcedureRefVO[procedureVOS.length];
        for (int i = 0; i < procedureVOS.length; i++) {
            ProcedureRefVO procedureRefVO = new ProcedureRefVO();
            procedureRefVO.setPkParent(procedureVOS[i].getPkParent());
            procedureRefVO.setPkProcedure(procedureVOS[i].getPkProcedure());
            procedureRefVO.setPkRoot(procedureVOS[i].getPkRoot());
            procedureRefVO.setScode(procedureVOS[i].getScode());
            procedureRefVO.setSname(procedureVOS[i].getSname());
            procedureRefVOS[i] = procedureRefVO;
        }
        return ArrayUtils.isEmpty(procedureRefVOS) ? new ProcedureRefVO[0] : procedureRefVOS;
    }

    @Override
    public Map<String, List<ProcedureRefVO>> queryRefByProjectIds(String[] pkProjects, String tenantId) throws BusinessException {
        if (pkProjects == null || pkProjects.length <= 0) {
            return new HashMap<>();
        }

        // 查询该项目下的工序
        Map<String, List<ProceprojectVO>> refProjectMap = proceprojectQryService.queryRefProjectByProjectIds(pkProjects);

        if (refProjectMap == null) {
            return new HashMap<>();
        }

        Set<String> procedureIdSet = new HashSet<>();
        for (Map.Entry<String, List<ProceprojectVO>> entry : refProjectMap.entrySet()) {
            for (ProceprojectVO refProjectVO : entry.getValue()) {
                procedureIdSet.add(refProjectVO.getPkProcedure());
            }
        }

        // 查询工序信息
        ProcedureVO[] procedureVOS = mapper.queryProcedureByRoots(procedureIdSet.toArray(new String[]{}));

        ProcedureRefVO[] procedureRefVOS = setProcedureInfo(procedureVOS);

        ProcedureRefVO[] newProcedureRefVOS = setProcedureDetailInfo(procedureRefVOS);

        Map<String, ProcedureRefVO> procedureRefVOMap = new HashMap<>();
        for(ProcedureRefVO procedureRefVO : newProcedureRefVOS ){
            procedureRefVOMap.put(procedureRefVO.getPkProcedure(), procedureRefVO);
        }

        // 根据项目主键对工序进行分组
        Map<String, List<ProcedureRefVO>> procedureRefMap = new HashMap<>();
        for (Map.Entry<String, List<ProceprojectVO>> entry : refProjectMap.entrySet()) {
            List<ProcedureRefVO> procedureRefVOList = new ArrayList<>();
            for (ProceprojectVO refProjectVO : entry.getValue()) {
                procedureRefVOList.add(procedureRefVOMap.get(refProjectVO.getPkProcedure()));
            }
            procedureRefMap.put(entry.getKey(), procedureRefVOList);
        }
        return procedureRefMap;
    }

    private ProcedureRefVO[] setProcedureDetailInfo(ProcedureRefVO[] procedureRefVOS) throws BusinessException {
        if(procedureRefVOS == null || procedureRefVOS.length <= 0){
            return new ProcedureRefVO[0];
        }
        Set<String> procedureIdSet = new HashSet<>();
        for (ProcedureRefVO procedureRefVO : procedureRefVOS) {
                procedureIdSet.add(procedureRefVO.getPkProcedure());
        }
        // 查询工序下的检查标准
        Map<String, Map<String, List<WorkqualityVO>>> qualityMap = workqualityQueryService.queryByProcedureIds(procedureIdSet);

        for(ProcedureRefVO procedureRefVO : procedureRefVOS){
            Map<String, List<WorkqualityVO>> workQualityMap = qualityMap.get(procedureRefVO.getPkProcedure());
            procedureRefVO.setWorkQualityMap(workQualityMap == null ? new HashMap<String, List<WorkqualityVO>>() : workQualityMap);
        }

        return buildResultVOs(procedureRefVOS);
    }

    private ProcedureRefVO[] buildResultVOs(ProcedureRefVO[] allVOs) {
        // 构造树
        Map<String, List<ProcedureRefVO>> procedureChildMap = new HashMap<>();
        for (ProcedureRefVO vo : allVOs) {
            String parent = vo.getPkParent();
            if (StringUtils.isEmpty(parent)) {
                parent = StringUtils.EMPTY;
            }
            List<ProcedureRefVO> children = procedureChildMap.get(parent);
            if (children == null) {
                children = new ArrayList<>();
                procedureChildMap.put(parent, children);
            }
            children.add(vo);
        }
        for (ProcedureRefVO vo : allVOs) {
            List<ProcedureRefVO> children = procedureChildMap.get(vo.getPkProcedure());
            if (children != null && children.size() > 0) {
                vo.setChildProcedure(children.toArray(new ProcedureRefVO[]{}));
            }
        }
        List<ProcedureRefVO> result = procedureChildMap.get(StringUtils.EMPTY);
        if (result == null) {
            return new ProcedureRefVO[0];
        } else {
            return result.toArray(new ProcedureRefVO[result.size()]);
        }
    }

    @Override
    public Object queryOffLineData(OffLineInvocationContext invocationContext) throws BusinessException {
        ProcedureRefVO[] procedureRefVOS = queryProcedureRefByTenant(invocationContext.getTenantId());
        return setProcedureDetailInfo(procedureRefVOS);
    }
}
